package org.redswallow.filter;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

import org.redswallow.filter.plugin.Plugin;
import org.redswallow.log.LogFactory;
import org.redswallow.util.config.ConfigConstants;
import org.redswallow.util.config.IPropertySet;
import org.redswallow.util.config.MappedPropertySet;
import org.slf4j.Logger;

public final class PluginFactory {
	
	public Plugin[] createPlugins() {
		
		Logger log = LogFactory.getLog(PluginFactory.class);
		ArrayList<Plugin> loadedPlugins = new ArrayList<Plugin>();
		
		IPropertySet props = RedSwallowContext.getInstance(null).getPropertySet();
		
		IPropertySet pluginsProps = new MappedPropertySet(ConfigConstants.REDSWALLOW_XSSCHECKER + ConfigConstants.CONFIG_PLUGIN, props);
		
		int pluginCount = pluginsProps.getInteger(ConfigConstants.CONFIG_COUNT, 0);
		
		log.info("Loading {} plugins...", pluginCount);
		
		for(int i=0; i<pluginCount; ++i) {
			
			String pluginInstance = pluginsProps.getString( "" + (i+1) + "." + ConfigConstants.CONFIG_NAME, null);
			if (pluginInstance!=null) {
				
				IPropertySet pluginProps = new MappedPropertySet(pluginInstance, pluginsProps);
				
				Class<?> pluginClass = pluginProps.getClass(ConfigConstants.CONFIG_CLASS, null);
				
				if (pluginClass == null) {
					log.info("Plugin class '{}' not found!", pluginProps.getString(ConfigConstants.CONFIG_CLASS, pluginInstance));
				}else {
					
					IPropertySet pluginParams = new MappedPropertySet(ConfigConstants.CONFIG_CONFIG, pluginProps);
					
					Plugin plugin = null;
			        try {
			            Constructor<?> constructor = pluginClass.getDeclaredConstructor(IPropertySet.class);
			            plugin = (Plugin) constructor.newInstance(pluginParams);
			        } catch (NoSuchMethodException e) {
			            log.debug("cannot instantiate module - constructor with PropertySet param not found", e);
			        } catch (InstantiationException e) {
			            log.debug("cannot instantiate module - InstantiationException", e);
			        } catch (InvocationTargetException e) {
			            log.debug("cannot instantiate module - InvocationTargetException", e);
			        } catch (IllegalAccessException e) {
			            log.debug("cannot instantiate module - IllegalAccessException", e);
			        }
			        
					if (plugin==null) {
						log.debug("plugin not yet instantiated, trying via default constructor");
		                try {
							plugin = (Plugin) pluginClass.newInstance();
						} catch (InstantiationException e) {
							log.error("cannot instantiate module", e);
						} catch (IllegalAccessException e) {
							log.error("cannot instantiate module", e);
						}
					}
					
					if (plugin != null) {
						loadedPlugins.add(plugin);
						
						log.info("Plugin Name    : {}" , plugin.getName());
	                    log.info("Plugin Version : {}" , plugin.getVersion());
	                    log.info("Plugin Vendor  : {}" , plugin.getVendor());
					}else {
						log.info("Plugin class '{}' cannot instantiate!", pluginProps.getString(ConfigConstants.CONFIG_CLASS, pluginInstance));
					}
					
				}
				
			}else {
				log.info("Plugin 'index:{}' not config .", i+1);
			}
		}
		
		return loadedPlugins.toArray(new Plugin[loadedPlugins.size()]);
		
	}
	
	
}
